package expr

import (
	"fmt"

	"github.com/pkg/errors"

	"gorm.io/gorm"

	"github.com/expr-lang/expr"
	"github.com/expr-lang/expr/ast"
	"github.com/expr-lang/expr/parser"
	
	"calculator/internal/core/schema"
)

// Evaluator 表达式求值器
type Evaluator struct {
	env          map[string]interface{}
	functions    map[string]interface{}
	db           *gorm.DB
	currentTable string
}

// NewEvaluator 创建新的表达式求值器
func NewEvaluator(db *gorm.DB) *Evaluator {
	return &Evaluator{
		env:       make(map[string]interface{}),
		functions: make(map[string]interface{}),
		db:        db,
	}
}

// RegisterFunctions 注册自定义函数
func (e *Evaluator) RegisterFunctions() {
	// 注册cur()函数 - 获取当前记录
	e.functions["cur"] = func() (map[string]interface{}, error) {
		record, ok := e.env["current_record"]
		if !ok {
			return nil, errors.Errorf("EXPR001: 当前记录不存在")
		}
		return record.(map[string]interface{}), nil
	}

	// 注册index()函数 - 通过索引查询记录
	e.functions["index"] = func(tableName string, indexField string, indexValue interface{}) (map[string]interface{}, error) {
		if e.db == nil {
			return nil, errors.Errorf("EXPR002: db实例未初始化")
		}

		db := e.db.Table(tableName)

		var result map[string]interface{}
		err := db.Where(fmt.Sprintf("%s = ?", indexField), indexValue).First(&result).Error
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, errors.Errorf("未找到匹配记录: tableName=%s, indexField=%s, indexValue=%v", tableName, indexField, indexValue)
			}
			return nil, errors.Wrapf(err, "EXPR002: tableName=%s, indexField=%s, indexValue=%v", tableName, indexField, indexValue)
		}
		return result, nil
	}

	// 注册record()函数 - 通过条件查询单条记录
	e.functions["record"] = func(tableName string, condition map[string]interface{}) (map[string]interface{}, error) {
		if e.db == nil {
			return nil, errors.Errorf("EXPR003: db实例未初始化")
		}

		db := e.db.Table(tableName)

		for key, value := range condition {
			db = db.Where(key+" ?", value)
		}

		var result map[string]interface{}
		err := db.Take(&result).Error
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, errors.Errorf("未找到匹配记录: tableName=%s", tableName)
			}
			return nil, errors.Wrapf(err, "EXPR003: tableName=%s", tableName)
		}
		return result, nil
	}

	// 注册records()函数 - 通过条件查询多条记录
	e.functions["records"] = func(tableName string, condition map[string]interface{}) ([]map[string]interface{}, error) {
		if e.db == nil {
			return nil, errors.Errorf("EXPR004: db实例未初始化")
		}

		db := e.db.Table(tableName)

		for key, value := range condition {
			db = db.Where(key+" ?", value)
		}

		var results []map[string]interface{}
		err := db.Find(&results).Error
		if err != nil {
			return nil, errors.Wrapf(err, "EXPR004: tableName=%s", tableName)
		}
		return results, nil
	}

	// 注册field()函数 - 从记录中获取字段值
	e.functions["field"] = func(record map[string]interface{}, fieldName string) (interface{}, error) {
		value, ok := record[fieldName]
		if !ok {
			return nil, errors.Errorf("字段不存在: fieldName=%s", fieldName)
		}
		return value, nil
	}

	// 注册expr()函数 - 基于单条记录计算表达式
	e.functions["expr"] = func(record map[string]interface{}, expression string) (interface{}, error) {
		// 设置当前记录
		e.SetUsingRecord(record)
		// 计算表达式
		result, err := e.Evaluate(expression)
		return result, err
	}

	// 注册exprs()函数 - 基于多条记录计算表达式
	e.functions["exprs"] = func(records []map[string]interface{}, expression string) ([]interface{}, error) {
		results := make([]interface{}, len(records))
		for i, record := range records {
			// 设置当前记录
			e.SetUsingRecord(record)
			// 计算表达式
			result, err := e.Evaluate(expression)
			if err != nil {
				return nil, err
			}
			results[i] = result
		}
		return results, nil
	}
}

// SetCurrentTable 设置当前表名
func (e *Evaluator) SetCurrentTable(tableName string) {
	e.currentTable = tableName
}

// SetCurrentRecord 设置当前记录
func (e *Evaluator) SetCurrentRecord(record map[string]interface{}) {
	e.env["current_record"] = record
	e.env["using_record"] = record
}

// SetUsingRecord 设置正在被使用的记录
func (e *Evaluator) SetUsingRecord(record map[string]interface{}) {
	e.env["using_record"] = record
}

// getEnv 获取环境变量
func (e *Evaluator) getEnv() map[string]interface{} {
	// 合并环境变量和函数
	env := make(map[string]interface{})

	// 合并环境变量, 用于：支持在表达式中引用当前记录
	for k, v := range e.env {
		env[k] = v
	}

	// 将正在被使用的记录的字段直接注入到环境变量中，这样表达式可以直接引用字段名
	if currentRecord, ok := e.env["using_record"]; ok {
		if record, ok := currentRecord.(map[string]interface{}); ok {
			for fieldKey, fieldValue := range record {
				env[fieldKey] = fieldValue
			}
		}
	}

	// 合并自定义函数，支持在表达式中引用自定义函数
	for k, v := range e.functions {
		env[k] = v
	}
	return env
}

// Evaluate 计算表达式
func (e *Evaluator) Evaluate(exprStr string) (interface{}, error) {
	// 合并环境变量和函数
	env := e.getEnv()

	// 编译表达式
	program, err := expr.Compile(exprStr, expr.Env(env))
	if err != nil {
		return nil, errors.Wrapf(err, "EXPR006: expression=%s", exprStr)
	}

	// 执行表达式
	result, err := expr.Run(program, e.getEnv())
	if err != nil {
		return nil, errors.Wrapf(err, "EXPR007: expression=%s", exprStr)
	}

	return result, nil
}

// EvaluateExprField 专门计算EXPR字段的表达式
// 这个方法会设置当前记录并计算表达式，适用于EXPR角色字段
func (e *Evaluator) EvaluateExprField(record map[string]interface{}, expression string) (interface{}, error) {
	// 保存原始环境状态
	originalEnv := make(map[string]interface{})
	for k, v := range e.env {
		originalEnv[k] = v
	}

	// 设置当前记录
	e.SetCurrentRecord(record)

	// 计算表达式
	result, err := e.Evaluate(expression)
	if err != nil {
		// 恢复原始环境
		e.env = originalEnv
		return nil, err
	}

	// 恢复原始环境
		e.env = originalEnv
	return result, nil
}

// ExtractDependencies 提取表达式中的依赖项
func (e *Evaluator) ExtractDependencies(exprStr string, schema ...*schema.Schema) ([]Dependency, error) {
	tree, err := parser.Parse(exprStr)
	if err != nil {
		return nil, errors.Wrapf(err, "EXPR006: 解析表达式失败: %s", exprStr)
	}

	// 使用增强的DependencyVisitor，设置当前表名
	visitor := NewDependencyVisitor().WithCurrentTable(e.currentTable)
	
	// 如果提供了Schema实例，设置到visitor中用于自动表名推断
	if len(schema) > 0 && schema[0] != nil {
		visitor = visitor.WithSchema(schema[0])
	}
	
	ast.Walk(&tree.Node, visitor)

	// 返回去重后的依赖项
	return visitor.GetDependencies(), nil
}
